package it.unical.canonaco.rende.igpe.game.cbv.guilayer.gamemanagermenu.storemenu.charshop;

import it.unical.canonaco.rende.igpe.game.cbv.guilayer.components.ImageCache;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.components.OverallGUILayoutFactory;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.components.ThinScrollBar;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.gamemanagermenu.storemenu.StorePanel;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.guievents.CharBoughtEvent;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.guievents.CharNameEvent;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.guievents.CharSoldEvent;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.guievents.CharacterClickEvent;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.guievents.GraphicEvent;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.guievents.GraphicEventListener;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.guievents.GraphicEventManager;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.guievents.ItemBoughtEvent;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.guievents.ItemSoldEvent;
import it.unical.canonaco.rende.igpe.game.cbv.guilayer.guievents.ShopCharClickEvent;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.pawn.Character;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.pawn.stats.Role;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.pawn.stats.StatsFactory;
import it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.managers.StoreManager;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.beans.PropertyChangeEvent;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.ImageIcon;
import javax.swing.InputVerifier;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.ScrollPaneConstants;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.DocumentFilter;
import javax.swing.text.MaskFormatter;
import javax.swing.text.StyledDocument;

public class CharShopPanel extends JPanel implements GraphicEventListener {

	private static String BUY = "COMPRA";
	private static String SELL = "VENDI";
	private static String CHAR_NAME = "NOME";
	private static String CHAR_PRICE = "PREZZO";
	private static String GOLD = "ORO";
	private JTextField nameField;
	private JLabel charPriceLabel;
	private JLabel charNameLabel;
	private JLabel playerGoldLabel = new JLabel();
	private StoreManager storeManager;
	private boolean validCharName = false;
	private GraphicEventManager gem;
	private DefaultListModel ownedCharListModel;
	private int currentCharIndex;
	private OverallGUILayoutFactory guiCreator = OverallGUILayoutFactory.getInstance();
	private JButton buyButton = guiCreator.createButtonUniState(40, BUY, 150,50, OverallGUILayoutFactory.BUTTON_STATE_ACTIVE);
	private JButton sellButton = guiCreator.createButtonUniState(40, SELL, 150,50, OverallGUILayoutFactory.BUTTON_STATE_ACTIVE);
	
	public CharShopPanel(final GraphicEventManager gem, final StoreManager storeManager,
			HashMap<String, String> settings, ImageCache imgCache, StatsFactory statsFactory, final DefaultListModel ownedCharListModel) {
		
		this.gem = gem;
		this.ownedCharListModel = ownedCharListModel;
		this.storeManager = storeManager;
		gem.addListener(this, CharBoughtEvent.class);
		gem.addListener(this, CharNameEvent.class);
		gem.addListener(this, CharSoldEvent.class);
		gem.addListener(this, ItemSoldEvent.class);
		gem.addListener(this, ItemBoughtEvent.class);
		
		charNameLabel = new JLabel(CHAR_NAME);
		charNameLabel.setFont(guiCreator.getHeaderFont().deriveFont(Font.PLAIN, 20));
		
		nameField = new JTextField(19);
		nameField.setTransferHandler(null);
		nameField.addFocusListener(new FocusListener(){
	        @Override
	        public void focusGained(FocusEvent e){
	        	
	        	nameField.setCaretPosition(nameField.getDocument().getLength());
	        	nameField.selectAll();
	        }

			@Override
			public void focusLost(FocusEvent arg0) {
			}
	    });
		Document doc = nameField.getDocument();
		if(doc instanceof AbstractDocument){
			AbstractDocument adoc = (AbstractDocument) doc;
			adoc.setDocumentFilter(new WordFilter(20));
		}
		buyButton.setEnabled(validCharName);
		Image coinImg = imgCache.getImage(settings.get(StorePanel.COIN_IMAGE));
		storeManager.calculateCharPrice();
		charPriceLabel = new JLabel(CHAR_PRICE+StorePanel.SPACE+storeManager.getCharPrice()+StorePanel.SPACE);
		charPriceLabel.setHorizontalTextPosition(JLabel.LEFT);
		charPriceLabel.setIcon(new ImageIcon(coinImg.getScaledInstance(coinImg.getWidth(null)/Integer.parseInt(settings.get(StorePanel.COIN_SCALE)),
				coinImg.getWidth(null)/Integer.parseInt(settings.get(StorePanel.COIN_SCALE)), Image.SCALE_SMOOTH)));
		charPriceLabel.setBackground(new Color(226,243,253,100));
		charPriceLabel.setOpaque(true);
		try {
			Font font = Font.createFont(Font.TRUETYPE_FONT, new File("cbvapps/uiresource/data/sharksoftbites.ttf"));
			charPriceLabel.setFont(font.deriveFont(Font.PLAIN,20));
		} catch (FontFormatException | IOException e) {
			e.printStackTrace();
		}
		
		playerGoldLabel.setHorizontalTextPosition(JLabel.LEFT);
		playerGoldLabel.setText(GOLD+StorePanel.SPACE+storeManager.getPlayer().getGold()+StorePanel.SPACE);
		playerGoldLabel.setIcon(new ImageIcon(coinImg.getScaledInstance(coinImg.getWidth(null)/Integer.parseInt(settings.get(StorePanel.COIN_SCALE)),
				coinImg.getWidth(null)/Integer.parseInt(settings.get(StorePanel.COIN_SCALE)), Image.SCALE_SMOOTH)));
		playerGoldLabel.setBackground(new Color(226,243,253,100));
		playerGoldLabel.setOpaque(true);
		try {
			Font font = Font.createFont(Font.TRUETYPE_FONT, new File("cbvapps/uiresource/data/sharksoftbites.ttf"));
			playerGoldLabel.setFont(font.deriveFont(Font.PLAIN,20));
		} catch (FontFormatException | IOException e) {
			e.printStackTrace();
		}
		
		sellButton.setPreferredSize(buyButton.getPreferredSize());
		this.setLayout(new GridBagLayout());
		this.setOpaque(false);
		GridBagConstraints gbc = new GridBagConstraints();
		DefaultListModel charListModel = new DefaultListModel();
		
//		final LinkedList<Character> characters = (LinkedList<Character>) storeManager.getPlayer().getCharacters();
		
		statsFactory.loadAllRoles();
		
		for(String role : statsFactory.getRoleNames() )
			charListModel.addElement(statsFactory.levellingRole(role, 1));
		
	
		
     	final JList charList = new JList(charListModel);
     	charList.setOpaque(false);
		charList.setVisibleRowCount(1);
		charList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		charList.setCellRenderer(new CharListRenderer(imgCache));
		charList.setLayoutOrientation(JList.HORIZONTAL_WRAP);
		JScrollPane scrollPane = new JScrollPane(charList, JScrollPane.VERTICAL_SCROLLBAR_NEVER,
               								JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
		
		scrollPane.setHorizontalScrollBar(new ThinScrollBar(JScrollBar.HORIZONTAL));
		scrollPane.setPreferredSize(new Dimension(500,150));
		scrollPane.setBackground(Color.WHITE);
//		scrollPane.setOpaque(false);
		scrollPane.getViewport().setOpaque(false);
		scrollPane.getViewport().setBorder(null);
		scrollPane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.DARK_GRAY.brighter(),2), 
				BorderFactory.createLineBorder(new Color(226,243,253,64),5) ));
		
		gbc.gridx = 0;
		gbc.gridy = 0;
		gbc.gridheight = 6;
		gbc.anchor = GridBagConstraints.FIRST_LINE_START;
		this.add(scrollPane, gbc);
		
		gbc.insets = new Insets(Integer.parseInt(settings.get(StorePanel.INSET_TOP)),
		Integer.parseInt(settings.get(StorePanel.INSET_LEFT)),Integer.parseInt(settings.get(StorePanel.INSET_BOTTOM)),
		Integer.parseInt(settings.get(StorePanel.INSET_RIGHT)));
		
		gbc.gridx = 1;
		gbc.gridheight = 1;
		this.add(charNameLabel, gbc);
		
		gbc.gridy = 1;
		this.add(nameField, gbc);
		
		gbc.gridy = 2;
		this.add(charPriceLabel, gbc);
		
		gbc.gridy = 3;
		this.add(buyButton, gbc);
		
		gbc.gridy = 4;
		this.add(sellButton, gbc);
		
		gbc.gridy = 5;
		this.add(playerGoldLabel, gbc);
		
		sellButton.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent arg0) {
				ownedCharListModel.remove(currentCharIndex);
				storeManager.sellCharacter(currentCharIndex);
				gem.fireEvent(new CharSoldEvent());
				
			}
		});
		
		buyButton.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent arg0) {

				Character newChar = storeManager.buyCharacter((Role) charList.getSelectedValue(), nameField.getText());
				gem.fireEvent(new CharBoughtEvent(newChar));
			}
		});
		
		
		charList.addListSelectionListener(new ListSelectionListener() {
			
			@Override
			public void valueChanged(ListSelectionEvent e) {
				
				//otherwise mouse click would fire this event twice
				if(!e.getValueIsAdjusting()){
				try {
					
					AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File("cbvapps"+File.separator+"sounds"+File.separator+"selectmenu.wav").getAbsoluteFile());
					Clip clip = AudioSystem.getClip();
					clip.open(audioInputStream);
					clip.start();
				} catch (LineUnavailableException | UnsupportedAudioFileException | IOException e1) {
					e1.printStackTrace();
				}
				
				JList list = (JList) e.getSource();
				Role clickedChar = (Role) list.getSelectedValue();
				gem.fireEvent(new ShopCharClickEvent(clickedChar));
				}
			}
		});
		
		charList.setSelectedIndex(0);
	}

	

	private class WordFilter extends DocumentFilter {
		int maxChars;
		
		public WordFilter(int maxChars) {
			this.maxChars = maxChars;
		}
		
		@Override 
		 public void replace(FilterBypass fb, int offset,
                 int length, String text, AttributeSet attr) throws BadLocationException {

			StringBuilder newStr = new StringBuilder(fb.getDocument().getText(0, fb.getDocument().getLength()));
			newStr.replace(offset, offset+length, text);
			if ((fb.getDocument().getLength() + text.length()) <= maxChars && newStr.toString().matches("\\w+(\\s|\\w)*"))
				super.replace(fb, offset, length, text, attr);
			
	        if(fb.getDocument().getLength()>0)
	        	validCharName = true;
	        else validCharName = false;
	        gem.fireEvent(new CharNameEvent());
}
		
		@Override
		public void remove(FilterBypass fb, int offset, int length)
				throws BadLocationException {

			//remove leading spaces. example: Cleric Azure, if u deleted Cleric,
			// there would be a leading space (not allowed)
			if(offset == 0){
				String text = fb.getDocument().getText(0, fb.getDocument().getLength());
			
				for(int i = length; i < text.length() && text.charAt(i) == ' '; i++)
						++length;
			}
			
			if(fb.getDocument().getLength()-length == 0)
				validCharName = false;
			super.remove(fb, offset, length);
			
			  gem.fireEvent(new CharNameEvent());
		}
	}


	@Override
	public void notify(GraphicEvent event) {
		Class eventClass = event.getClass();
		
		if(eventClass == CharBoughtEvent.class || eventClass == CharSoldEvent.class){
			storeManager.calculateCharPrice();
			charPriceLabel.setText(StorePanel.SPACE+storeManager.getCharPrice());
			if(storeManager.isCharSellable())
				sellButton.setEnabled(true);
			else sellButton.setEnabled(false);
		}
		
		if(eventClass == CharBoughtEvent.class || eventClass == CharNameEvent.class
				|| eventClass == CharSoldEvent.class || eventClass == ItemSoldEvent.class
				|| eventClass == ItemBoughtEvent.class){
			if(storeManager.isCharListFull() || !validCharName || !storeManager.isCharBuyable()
					|| !storeManager.isCharNameUnique(nameField.getText()))
				buyButton.setEnabled(false);
			else buyButton.setEnabled(true);
			
			
				
				playerGoldLabel.setText(GOLD+StorePanel.SPACE+storeManager.getPlayer().getGold()+StorePanel.SPACE);
			
			
		} else if(eventClass == CharacterClickEvent.class)
			currentCharIndex = ((CharacterClickEvent) event).getIndex();
		
		
	}
}
